home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / sviluppo / svilupp2 / amphn192.lha / src / ciatimer.c < prev    next >
C/C++ Source or Header  |  1996-11-16  |  51KB  |  1,714 lines

  1. #include <time.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5.  
  6. #include <exec/io.h>
  7. #include <exec/types.h>
  8. #include <exec/memory.h>
  9. #include <exec/tasks.h>
  10. #include <exec/interrupts.h>
  11. #include <exec/ports.h>
  12. #include <exec/lists.h>
  13. #include <hardware/cia.h>
  14. #include <hardware/intbits.h>
  15. #include <libraries/mathieeesp.h>
  16. #include <clib/mathieeedoubbas_protos.h>
  17.  
  18. #include <resources/cia.h>
  19.  
  20. #include <libraries/dos.h>
  21. #include <libraries/delfina.h>
  22. #include <resources/misc.h>
  23. #include <utility/tagitem.h>
  24.  
  25. #include <pragmas/ahi_pragmas.h>
  26.  
  27. #include <devices/ahi.h>
  28. #include <clib/alib_protos.h>
  29. #include <clib/ahi_protos.h>
  30. #include <clib/dos_protos.h>
  31. #include <clib/cia_protos.h>
  32. #include <clib/exec_protos.h>
  33. #include <clib/misc_protos.h>
  34.  
  35. #include "AmiPhoneMsg.h"
  36. #include "AmiPhone.h"
  37. #include "phoneudp.h"
  38. #include "ciatimer.h"
  39. #include "messages.h"
  40. #include "codec.h"
  41. #include "delfph.h"
  42.  
  43. #include "toccata/include/libraries/toccata.h"
  44. #include "toccata/include/clib/toccata_protos.h"
  45. #include "toccata/include/pragmas/toccata_pragmas.h"
  46.  
  47. /* Some hardware addresses to sample from */
  48. #define AMIGA_HARDWARE_SAMPLE_ADDRESS     ((UBYTE *) (&pciaa->ciaprb))
  49. #define AURA_SAMPLE_ADDRESS_LEFT      ((UBYTE *) 0xA20000)
  50. #define AURA_SAMPLE_ADDRESS_RIGHT     ((UBYTE *) 0xA20002)
  51.  
  52.     
  53. /*
  54.  * Structure which will be used to hold all relevant information about
  55.  * the cia timer we manage to allocate.
  56.  *
  57.  */
  58.  
  59. struct freetimer
  60. {
  61.     struct Library * ciabase;    /* CIA Library Base */
  62.     ULONG  timerbit;        /* timer bit allocated */
  63.     struct CIA *cia;        /* ptr to hardware */
  64.     UBYTE  * ciacr;            /* ptr to control register */
  65.     UBYTE  * cialo;            /* ptr to low byte of timer */
  66.     UBYTE  * ciahi;            /* ptr to high byte of timer */
  67.     struct Interrupt timerint;    /* interrupt structure */
  68.     UBYTE  stopmask;        /* Stop/Setup timer */
  69.     UBYTE  startmask;        /* Start timer */
  70.     BOOL   BUsingCIAB;        /* TRUE if CIAB, FALSE if CIAA */
  71. };
  72.  
  73.  
  74. /* function exported to inthandler.a */
  75. void SetTimerCountdown(struct freetimer * ft, UWORD uwMicros);
  76.  
  77. /* external data */
  78. extern void AHIhookEntry();        /* hook stub */
  79. extern void Idle();            
  80. extern void InvertIdle();
  81. extern void PerfectIdle();
  82. extern void Record();          /* prototype for assembly interrupt routine */
  83. extern void PerfectRecord();   /* prototype for assembly interrupt routine */
  84.  
  85. extern BOOL BTransmitting, BSoundOn, BButtonHeld, BSpaceTapped, BTCPBatchXmit, BUserDebug;
  86. extern UBYTE ubSamplerType, ubInputChannel, ubCurrComp, ubInputSource;
  87. extern UBYTE ubCustStart, ubCustStop, ubCustLeft, ubCustRight, ubCustMic, ubCustExt, ubCustDir;
  88. extern UBYTE * pubCustSampleAt;
  89. extern ULONG ulSampleArraySize;
  90. extern ULONG ulBytesPerSecond;
  91. extern ULONG ulLastVolume;
  92. extern ULONG ulTimerDelay;
  93. extern ULONG ulKeyCode;
  94. extern ULONG ulIdleRate;
  95. extern float fPacketDelay;
  96. extern int nHackAmpVol, nAnimFrame, nMinSampleVol, nSampleTechnique, nToggleMode, nMaxSampleRate, nAmpShift;
  97. extern int nPreSendQLen, nPostSendLen;
  98. extern struct AmiPhoneSendBuffer sendBuf;
  99. extern char szProgramName[];
  100. extern struct Task * MainTask;
  101.  
  102. extern struct Library * AHIBase;
  103. extern struct Library * ToccataBase;
  104. extern struct Library * DelfinaBase;
  105.  
  106. /* data */
  107. struct IntInfo IntData;
  108. BYTE sighalf=0, sigfull=0;
  109. UBYTE * pubAllocedArray = NULL;
  110. UBYTE * pubRightBuffer  = NULL;
  111. int nLineGainValue=0, nMicGainValue=20;
  112. UBYTE * pubBulkSamplePacket = NULL;
  113. ULONG   ulBulkSamplePacketLen, ulBulkSamplePacketSum, ulAHIAudioMode = 0L;
  114.  
  115. /* private data */
  116. static ULONG ulAllocedArraySize = 0L;
  117. static ULONG CalcSampleArraySize(ULONG ulBPS, BYTE bComp, float fPackDelay);
  118. static struct MsgPort * ToccataReplyPort;
  119. static struct AHIAudioCtrl * AHIAudioControl = NULL;
  120. static struct freetimer AmiPhoneTimer;
  121. static struct List * PreSendQueue = NULL;
  122. static int nCurrentPreSendQLen;
  123.  
  124. /* private function prototypes */
  125. static BOOL StartTimer(struct freetimer * ft, UWORD uwMicros, ULONG ulSmallestArraySize);
  126. static BOOL FindFreeTimer(struct freetimer *ft);
  127. static BOOL TryTimer(struct freetimer *ft);
  128. static BOOL AllocSamplingBuffer(ULONG ulSmallestArraySize);
  129. static UWORD BPSToMicros(ULONG ulBPS);
  130. static void IdleSampler(void);
  131. static ULONG AHI_FindFrequency(ULONG ulBPS);
  132. static void FlushPreSendQueue(BOOL BTransmit, BOOL BTCP);
  133. static void UpdatePreSendQueue(struct AmiPhoneSendBuffer * sBuf);
  134. static void FreePreSendNode(struct Node * current);
  135.  
  136. /* Used by toccata & AHI samplers */
  137. static __geta4 BOOL ToccataSendData(UBYTE * ubData, ULONG ulDataSize);
  138. static __geta4 ULONG AHISendData(struct Hook *hook, struct AHIAudioCtrl * ctrl, struct AHIRecordMessage * msg);
  139. static BOOL StartToccataCapture(BOOL BStart, ULONG ulBPS);
  140. static BOOL StartAHICapture(BOOL BStart, ULONG ulBPS);
  141. static BOOL StartDelfinaCapture(BOOL BStart, ULONG ulBPS);
  142.  
  143. /* Front-ends to setting the various data direction and control bits on the parallel port */
  144. static void SetDirectionBits(UBYTE ubBitCode);
  145. static void SetParallelBits(int nEvent, UBYTE ubBitCode);
  146. static char * BitsToString(UBYTE ubCode);
  147. static char * RegToString(UBYTE ubReg);
  148.  
  149. #define EVENT_NONE  0
  150. #define EVENT_START 1
  151. #define EVENT_STOP  2
  152. #define EVENT_LEFT  3
  153. #define EVENT_RIGHT 4
  154. #define EVENT_MIC   5
  155. #define EVENT_EXT   6
  156.  
  157. char * szEventStrings[] = {
  158.   "",
  159.   "enable sampler",
  160.   "disable sampler",
  161.   "change to left channel",
  162.   "change to right channel",
  163.   "change to mic input",
  164.   "change to external input"};
  165.  
  166. #define STOPA_AND    (CIACRAF_TODIN | CIACRAF_PBON | CIACRAF_OUTMODE | CIACRAF_SPMODE)
  167.  
  168.     /*
  169.     ;
  170.     ; AND mask for use with control register A 
  171.     ; (interval timer A on either CIA)
  172.     ;
  173.     ; STOP -
  174.     ;     START bit 0 == 0 (STOP IMMEDIATELY)
  175.     ;     PBON  bit 1 == same
  176.     ;     OUT   bit 2 == same
  177.     ;    RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  178.     ;    LOAD  bit 4 == 0 (NO FORCE LOAD)
  179.     ;    IN    bit 5 == 0 (COUNTS 02 PULSES)
  180.     ;    SP    bit 6 == same
  181.     ;    TODIN bit 7 == same (unused on ciacra)
  182.     ;
  183.     */
  184.     
  185. #define STOPB_AND    (CIACRBF_ALARM | CIACRBF_PBON | CIACRBF_OUTMODE)
  186.  
  187.     /*
  188.     ;
  189.     ; AND mask for use with control register B 
  190.     ; (interval timer B on either CIA)
  191.     ;
  192.     ; STOP -
  193.     ;     START bit 0 == 0 (STOP IMMEDIATELY)
  194.     ;     PBON  bit 1 == same
  195.     ;     OUT   bit 2 == same
  196.     ;    RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  197.     ;    LOAD  bit 4 == 0 (NO FORCE LOAD)
  198.     ;    IN0   bit 5 == 0 (COUNTS 02 PULSES)
  199.     ;    IN1   bit 6 == 0 (COUNDS 02 PULSES)
  200.     ;    ALARM bit 7 == same (TOD alarm control bit)
  201.     ;
  202.     */
  203.  
  204. #define STARTA_OR    CIACRAF_START
  205.  
  206.     /*
  207.     ;
  208.     ; OR mask for use with control register A
  209.     ; (interval timer A on either CIA)
  210.     ;
  211.     ; START -
  212.     ;
  213.     ;    START bit 0 == 1 (START TIMER)
  214.     ;
  215.     ;    All other bits unaffected.
  216.     ;
  217.     */
  218.     
  219. #define STARTB_OR    CIACRBF_START
  220.  
  221.     /*
  222.     ;
  223.     ; OR mask for use with control register B
  224.     ; (interval timer A??? on either CIA)
  225.     ;
  226.     ; START -
  227.     ;
  228.     ;    START bit 0 == 1 (START TIMER)
  229.     ;
  230.     ;    All other bits unaffected.
  231.     ;
  232.     */
  233.  
  234.  
  235.  
  236. extern struct CIA ciaa;
  237. extern struct CIA ciab;
  238.  
  239. struct CIA *pciaa = &ciaa;
  240. struct CIA *pciab = &ciab;    
  241.  
  242. /* Safe conversion function */
  243. static UWORD BPSToMicros(ULONG ulBPS) 
  244. {
  245.     UWORD uwMaxWord = ((UWORD)(-1));
  246.     ULONG ulTemp = 715820L / (ulBPS ? ulBPS : 1L);
  247.  
  248.     if (ulTemp > uwMaxWord) ulTemp = uwMaxWord;
  249.     
  250.     return((UWORD) ulTemp);
  251. }
  252.  
  253.  
  254.  
  255. /* If the argument is FALSE, records the current state of the
  256.    digitizer.  If it is TRUE, resets the digitizer to the state
  257.    that was previously recorded. */
  258. void ResetDigitizer(BOOL BReset)
  259. {
  260.     static int PrevSource = 9999;
  261.     BOOL BWasInput;
  262.  
  263.     if (BReset == FALSE)
  264.     {
  265.         /* Other items may be added later */
  266.         switch(ubSamplerType)
  267.         {
  268.             case SAMPLER_SOMAGIC:
  269.                 BWasInput = ((pciab->ciaddra & CIAF_PRTRBUSY) == 0);
  270.                      pciab->ciaddra &= ~(CIAF_PRTRBUSY); /* set this line to input so we can read it */
  271.                 PrevSource = (pciab->ciapra & CIAF_PRTRBUSY) ? INPUT_SOURCE_EXT : INPUT_SOURCE_MIC;
  272.                 UNLESS(BWasInput) pciab->ciaddra |= CIAF_PRTRBUSY;    /* put it back to original state */
  273.                 break;
  274.         }
  275.     }
  276.     else
  277.     {
  278.         switch(ubSamplerType)
  279.         {
  280.             case SAMPLER_SOMAGIC:
  281.                 BWasInput = ((pciab->ciaddra & CIAF_PRTRBUSY) == 0);
  282.                 pciab->ciaddra |= CIAF_PRTRBUSY;
  283.                 ChangeInputSource(PrevSource,FALSE);    /* don't want this to be reflected in the menus! */
  284.                 UNLESS (BWasInput) pciab->ciaddra |= CIAF_PRTRBUSY;
  285.                 break;
  286.         }
  287.     }
  288. }
  289.  
  290. void ChangeSamplerType(int nNewSamplerType)
  291. {    
  292.     BOOL BWasTransmitting = BTransmitting;
  293.     
  294.     if ((nNewSamplerType < 0)||(nNewSamplerType >= SAMPLER_MAX)) return;
  295.     if ((nNewSamplerType == SAMPLER_DELFINA)&&(!DelfinaBase)) return;
  296.     if ((nNewSamplerType == SAMPLER_TOCCATA)&&(!ToccataBase)) return;
  297.     if ((nNewSamplerType == SAMPLER_AHI)&&(!AHIBase)) return;
  298.     
  299.     if (BWasTransmitting) ToggleMicButton(CODE_OFF);
  300.     
  301.     ubSamplerType = nNewSamplerType;
  302.     ChangeInputChannel(ubInputChannel);
  303.     ChangeInputSource(ubInputSource,TRUE);
  304.  
  305.     if (BWasTransmitting) ToggleMicButton(CODE_ON);
  306. }
  307.  
  308.  
  309.     
  310. void ChangeInputSource(int nNewSource, BOOL BMakeCurrentMode)
  311. {
  312.     struct TagItem taglist[3];
  313.     
  314.     if (BMakeCurrentMode) ubInputSource = nNewSource;
  315.     
  316.     switch(ubSamplerType)
  317.     {
  318.         case SAMPLER_TOCCATA:
  319.             taglist[0].ti_Tag  = PAT_Input;        
  320.             switch (ubInputSource)
  321.             {
  322.                 case INPUT_SOURCE_MIC: taglist[0].ti_Data = TINPUT_Mic;  break;
  323.                 case INPUT_SOURCE_EXT: taglist[0].ti_Data = TINPUT_Line; break;
  324.             }
  325.             taglist[1].ti_Tag  = TAG_DONE;    taglist[1].ti_Data = NULL;
  326.             T_SetPart(taglist);
  327.             break;
  328.         
  329.         case SAMPLER_SOMAGIC:
  330.             switch(nNewSource)
  331.             {
  332.                 case INPUT_SOURCE_MIC: SetParallelBits(EVENT_NONE, SAMPBIT_BUSYCLR); break;
  333.                 case INPUT_SOURCE_EXT: SetParallelBits(EVENT_NONE, SAMPBIT_BUSYSET); break;
  334.             }
  335.             break;
  336.     
  337.         case SAMPLER_DELFINA:
  338.             taglist[0].ti_Tag = DA_MicIn;    taglist[0].ti_Data = (nNewSource == INPUT_SOURCE_MIC);
  339.             taglist[1].ti_Tag = DA_LineIn;    taglist[1].ti_Data = (nNewSource == INPUT_SOURCE_EXT);
  340.             taglist[2].ti_Tag = TAG_DONE;    taglist[2].ti_Data = NULL;
  341.             Delf_SetAttrsA(taglist);
  342.             break;
  343.                 
  344.         case SAMPLER_CUSTOM:
  345.             switch(ubInputSource)
  346.             {
  347.                 case INPUT_SOURCE_MIC: SetParallelBits(EVENT_MIC,ubCustMic); break;
  348.                 case INPUT_SOURCE_EXT: SetParallelBits(EVENT_EXT,ubCustExt); break;
  349.             }
  350.     }
  351. }
  352.  
  353.  
  354. void ChangeInputChannel(int nNewChannel)
  355. {
  356.     if (nNewChannel == INPUT_JACK_LEFT) 
  357.     {
  358.         switch (ubSamplerType)
  359.         {
  360.             case SAMPLER_TOCCATA:
  361.                  break;
  362.                         
  363.             case SAMPLER_GVPDSS8:     /* this verified to work by JAF */
  364.                  SetParallelBits(EVENT_NONE,SAMPBIT_SELSET);
  365.                    break;        
  366.                  
  367.             case SAMPLER_SOMAGIC:
  368.                  SetParallelBits(EVENT_NONE,SAMPBIT_POUTCLR | SAMPBIT_SELSET);
  369.                   break;
  370.  
  371.             case SAMPLER_AURA:
  372.                  IntData.pubSampleAt = AURA_SAMPLE_ADDRESS_LEFT;
  373.                  break;
  374.                  
  375.             case SAMPLER_CUSTOM:
  376.                  SetParallelBits(EVENT_LEFT,ubCustLeft);
  377.                  if (pubCustSampleAt) IntData.pubSampleAt = pubCustSampleAt;
  378.                  break;        
  379.             
  380.             case SAMPLER_DELFINA:
  381.                  if (StartSampling(CHECK_STATUS,0) == TRUE) 
  382.                  {
  383.                     ubInputChannel = INPUT_JACK_LEFT;    /* must be set BEFORE the StartSampling pair! */
  384.                     BTransmitting = StartSampling(FALSE,0);
  385.                     BTransmitting = StartSampling(TRUE,ulBytesPerSecond);
  386.                  }
  387.                  break;
  388.                                       
  389.             default: case SAMPLER_PERFECT: case SAMPLER_AMAS: 
  390.                  /* as described by Marcel Offermans & AGMSRecordSound author */
  391.                  SetParallelBits(EVENT_NONE,SAMPBIT_SELCLR);
  392.                  break;
  393.         }
  394.     }
  395.     else if (nNewChannel == INPUT_JACK_RIGHT) 
  396.     {
  397.         switch (ubSamplerType)
  398.         {
  399.             case SAMPLER_TOCCATA:
  400.                  break;
  401.             
  402.             case SAMPLER_DELFINA:
  403.                  if (StartSampling(CHECK_STATUS,0) == TRUE) 
  404.                  {
  405.                     ubInputChannel = INPUT_JACK_RIGHT;    /* must be set BEFORE the StartSampling pair! */
  406.                     BTransmitting = StartSampling(FALSE,0);
  407.                     BTransmitting = StartSampling(TRUE,ulBytesPerSecond);
  408.                  }
  409.                  break;                          
  410.  
  411.             case SAMPLER_GVPDSS8: 
  412.                  SetParallelBits(EVENT_NONE, SAMPBIT_SELCLR);
  413.                  break;
  414.             
  415.             case SAMPLER_SOMAGIC:
  416.                  SetParallelBits(EVENT_NONE, SAMPBIT_SELCLR | SAMPBIT_POUTSET);
  417.                  break;
  418.  
  419.             case SAMPLER_AURA:
  420.                  IntData.pubSampleAt = AURA_SAMPLE_ADDRESS_RIGHT;
  421.                  break;                 
  422.  
  423.             case SAMPLER_CUSTOM:
  424.                  SetParallelBits(EVENT_RIGHT, ubCustRight);
  425.                  if (pubCustSampleAt) IntData.pubSampleAt = pubCustSampleAt;
  426.                  break;
  427.                                   
  428.             default: case SAMPLER_PERFECT: case SAMPLER_AMAS: 
  429.                  SetParallelBits(EVENT_NONE, SAMPBIT_POUTCLR | SAMPBIT_SELSET);
  430.                  break;
  431.         }
  432.     }
  433.     ubInputChannel = nNewChannel;
  434. }
  435.  
  436. /* Attempts to start or stop sampling, based on BStart. */
  437. /* Returns the (new) current state of the sampling timer.  TRUE=going, FALSE=stopped */
  438. BOOL StartSampling(BOOL BStart, ULONG ulBPS)
  439. {
  440.     static BOOL BTimerStarted = FALSE, BFirstTime = TRUE;
  441.     static struct Interrupt SoftInt;
  442.     UBYTE * pubPartialSend;
  443.     int nPartialSendLength;
  444.  
  445.     /* case where user just wants to check, case where user is already in desired state */    
  446.     if ((BStart == CHECK_STATUS)||(BStart == BTimerStarted)) return(BTimerStarted);
  447.  
  448.     /* Make sure our queue is empty */
  449.     FlushPreSendQueue(FALSE,FALSE);
  450.             
  451.     /* For the toccata board, we do something totally different */
  452.     if (ubSamplerType == SAMPLER_TOCCATA) return(BTimerStarted = StartToccataCapture(BStart, ulBPS));
  453.     
  454.     /* Not to mention for the AHI system, it's completely different as well */
  455.     if (ubSamplerType == SAMPLER_AHI) return(BTimerStarted = StartAHICapture(BStart, ulBPS));
  456.     
  457.     if (ubSamplerType == SAMPLER_DELFINA) return(BTimerStarted = StartDelfinaCapture(BStart, ulBPS));
  458.     
  459.     /* set up data which will be passed to interrupt */
  460.     if (BStart == TRUE)
  461.     {    
  462.         if (AllocParallel(TRUE,TRUE) == FALSE) return(FALSE);
  463.  
  464.         if (BFirstTime == TRUE)
  465.         {
  466.             ResetDigitizer(FALSE);    /* record state */
  467.             BFirstTime = FALSE;    
  468.         }
  469.         
  470.         /* Might as well make sure the settings are correct! */
  471.         ChangeInputChannel(ubInputChannel);
  472.         ChangeInputSource(ubInputSource,FALSE);
  473.         
  474.         /* Prepare freetimer structure: setup hardware interrupt */
  475.         AmiPhoneTimer.timerint.is_Node.ln_Type = NT_INTERRUPT;
  476.         AmiPhoneTimer.timerint.is_Node.ln_Pri  = 0;
  477.         AmiPhoneTimer.timerint.is_Node.ln_Name = "AmiPhone Sample Timer";
  478.         AmiPhoneTimer.timerint.is_Data           = (APTR) &IntData;
  479.         AmiPhoneTimer.timerint.is_Code           = (ubSamplerType == SAMPLER_PERFECT) ? PerfectIdle : ((UsesInvertedSamples()) ? InvertIdle : Idle);
  480.         
  481.         /* Call function to find a free CIA interval timer
  482.          * with flag indicating that we prefer a CIA timer A.
  483.          */
  484.         if (FindFreeTimer(&AmiPhoneTimer))
  485.         {
  486.             /* use BPS to figure out # of microseconds to delay between samples */
  487.             ulTimerDelay = BPSToMicros(ulBPS);
  488.             
  489.             /* Start it up! */
  490.             UNLESS(BTimerStarted = StartTimer(&AmiPhoneTimer, ulTimerDelay, ulSampleArraySize))
  491.             {
  492.                 AllocParallel(FALSE,FALSE);
  493.                 UserError("Couldn't start CIA Timer");
  494.             }
  495.         }
  496.         else 
  497.         {
  498.             SetWindowTitle("Error: no CIA timers available.");
  499.             AllocParallel(FALSE,FALSE);
  500.         }
  501.     }
  502.     else
  503.     {
  504.         /* Turn off CIA interrupt if we were using it */
  505.         if ((nSampleTechnique == TECHNIQUE_SOFTINT)||(nSampleTechnique == TECHNIQUE_HARDINT))
  506.             RemICRVector(AmiPhoneTimer.ciabase, AmiPhoneTimer.timerbit, &AmiPhoneTimer.timerint);
  507.  
  508.         /* If the user wants to do something on disable, here's where! */
  509.         if (ubSamplerType == SAMPLER_CUSTOM) SetParallelBits(EVENT_STOP, ubCustStop);
  510.         
  511.         /* Reset to initial state */
  512.         ResetDigitizer(TRUE);
  513.  
  514.         /* Deallocate parallel port */
  515.         AllocParallel(FALSE,FALSE);
  516.         BTimerStarted = FALSE;
  517.  
  518.         /* Send what we have of the current packet, if we were sending */
  519.         pubPartialSend     = (IntData.pubIndex >= IntData.pubHalfIndex) ? IntData.pubHalfIndex : IntData.pubArray;
  520.         nPartialSendLength = (int) (IntData.pubIndex-pubPartialSend);
  521.         if (nPartialSendLength == 0) nPartialSendLength = 1;
  522.                 
  523.         /* pro-rate the partial sample's volume to represent the full range */
  524.         IntData.ulSaveByteSum = ((ULONG) (IntData.ulByteSum * ((ULONG)(IntData.pubHalfIndex-IntData.pubArray)))) / ((ULONG) nPartialSendLength);
  525.         TransmitData(pubPartialSend, nPartialSendLength, ubCurrComp);                
  526.         
  527.         /* Deallocate any RAM that was previously allocated */
  528.         AllocSamplingBuffer(0L);
  529.     
  530.         ulLastVolume = SILENCE;
  531.     }
  532.     return(BTimerStarted);
  533. };
  534.  
  535.  
  536.  
  537.  
  538.  
  539. static BOOL StartAHICapture(BOOL BStart, ULONG ulBPS)
  540. {
  541.     struct TagItem taglist[15];
  542.     static struct Hook RecordFuncHook;
  543.     ULONG ulAHIVolume,ulAHIRecord,ulAHIRealtime,ulAHIBits,ulAHIFrequencies,
  544.           ulAHIIndex,ulAHIMaxRecordSamples,ulBestAudioMode, ulError;
  545.     char szDriverName[200] = "szDriverName",
  546.          szModeName[200]   = "szModeName",
  547.          szAuthorName[200] = "szAuthorName",
  548.          szVersionName[200]= "szVersionName";
  549.     
  550.     if (BStart)
  551.     {
  552.         printf("StartAHICapture():  Setting up capture....\n");
  553.         
  554.         taglist[0].ti_Tag = AHIDB_Record; taglist[0].ti_Data = TRUE;
  555.         taglist[1].ti_Tag = AHIDB_Bits;   taglist[1].ti_Data = 8;
  556.         taglist[2].ti_Tag = TAG_DONE;      taglist[2].ti_Data = NULL;
  557.         ulBestAudioMode = AHI_BestAudioIDA(taglist);
  558.         
  559.         printf("ulBestAudioMode is 0x%X\n",ulBestAudioMode);
  560.         if (ulBestAudioMode == AHI_INVALID_ID) printf("Warning, INVALID ID!\n");
  561.         
  562.         taglist[0].ti_Tag  = AHIDB_Volume;     taglist[0].ti_Data  = &ulAHIVolume;
  563.         taglist[1].ti_Tag  = AHIDB_Record;     taglist[1].ti_Data  = &ulAHIRecord;
  564.         taglist[2].ti_Tag  = AHIDB_Realtime;     taglist[2].ti_Data  = &ulAHIRealtime;
  565.         taglist[3].ti_Tag  = AHIDB_Bits;     taglist[3].ti_Data  = &ulAHIBits;
  566.         taglist[4].ti_Tag  = AHIDB_Frequencies; taglist[4].ti_Data  = &ulAHIFrequencies;
  567.         taglist[5].ti_Tag  = AHIDB_Index;     taglist[5].ti_Data  = &ulAHIIndex;
  568.         taglist[6].ti_Tag  = AHIDB_IndexArg;     taglist[6].ti_Data  = ulBPS;
  569.         taglist[7].ti_Tag  = AHIDB_MaxRecordSamples; taglist[7].ti_Data = &ulAHIMaxRecordSamples;
  570.         taglist[8].ti_Tag  = AHIDB_BufferLen;   taglist[8].ti_Data  = sizeof(szDriverName);
  571.         taglist[9].ti_Tag  = AHIDB_Driver;     taglist[9].ti_Data  = szDriverName;
  572.         taglist[10].ti_Tag = AHIDB_Name;     taglist[10].ti_Data = szModeName;
  573.         taglist[11].ti_Tag = AHIDB_Author;     taglist[11].ti_Data = szAuthorName;
  574.         taglist[12].ti_Tag = AHIDB_Version;    taglist[12].ti_Data = szVersionName;
  575.         taglist[13].ti_Tag = TAG_DONE;         taglist[13].ti_Data = NULL;
  576.         UNLESS(AHI_GetAudioAttrsA(ulBestAudioMode, NULL, taglist))
  577.         {
  578.             printf("AHI_GetAudioAttrsA failed!\n");
  579.             return(FALSE);
  580.         }
  581.  
  582.         printf("---------AHI_GetAudioAttrs reports:\n");
  583.         printf("VolumeAdjustable = %lu\n",ulAHIVolume);
  584.         printf("CanRecord        = %lu\n",ulAHIRecord);
  585.         printf("Realtime         = %lu\n",ulAHIRealtime);
  586.         printf("BitsPerSample    = %lu\n",ulAHIBits);
  587.         printf("NumFrequencies   = %lu\n",ulAHIFrequencies);
  588.         printf("IndexOf(f=%lu)   = %lu\n",ulBPS,ulAHIIndex);
  589.         printf("MaxRecordSamples = %lu\n",ulAHIMaxRecordSamples);
  590.         printf("szDriverName  = [%s]\n",szDriverName);
  591.         printf("szModeName    = [%s]\n",szModeName);
  592.         printf("szAuthorName  = [%s]\n",szAuthorName);
  593.         printf("szVersionName = [%s]\n",szVersionName);
  594.         printf("---------End AHI_GetAudioAttrs\n");
  595.  
  596.         /* Setup our Hook! */
  597.         RecordFuncHook.h_Entry    = (ULONG (*) ()) AHIhookEntry;
  598.         RecordFuncHook.h_SubEntry = AHISendData;
  599.         RecordFuncHook.h_Data      = NULL;    /* Should there be something here? */
  600.         
  601.         /* Now start the capture */
  602.         taglist[0].ti_Tag = AHIA_AudioID;     taglist[0].ti_Data = ulBestAudioMode;
  603.         taglist[1].ti_Tag = AHIA_Channels;    taglist[1].ti_Data = 0;    /* Is zero channels okay since we won't be playing any sounds?? */
  604.         taglist[2].ti_Tag = AHIA_Sounds;      taglist[2].ti_Data = 0;    /* What is this arg, anyway??? */
  605.         taglist[3].ti_Tag = AHIA_RecordFunc;    taglist[3].ti_Data = &RecordFuncHook;
  606.         taglist[4].ti_Tag = TAG_DONE;          taglist[4].ti_Data = NULL;
  607.         UNLESS(AHIAudioControl = AHI_AllocAudioA(taglist))
  608.         {
  609.             SetWindowTitle("AHI_AllocAudioA failed!");
  610.             return(FALSE);
  611.         }
  612.         ulAHIAudioMode = ulBestAudioMode;
  613.         
  614.         taglist[0].ti_Tag = AHIC_Play;         taglist[0].ti_Data = FALSE;
  615.         taglist[1].ti_Tag = AHIC_Record;    taglist[1].ti_Data = TRUE;
  616.         taglist[2].ti_Tag = AHIA_RecordFunc;    taglist[2].ti_Data = &RecordFuncHook;
  617.         taglist[3].ti_Tag = TAG_DONE;          taglist[3].ti_Data = NULL;
  618.         if (ulError = AHI_ControlAudioA(AHIAudioControl, taglist))
  619.         {
  620.             printf("AHI_ControlAudioA failed, error %lu\n",ulError);
  621.             AHI_FreeAudio(AHIAudioControl); AHIAudioControl = NULL;
  622.             return(FALSE);
  623.         }
  624.         return(TRUE);
  625.     }
  626.     else
  627.     {
  628.         printf("StartAHICapture():  Ending capture....\n");
  629.         if (AHIAudioControl)
  630.         {
  631.             taglist[0].ti_Tag = AHIC_Play;         taglist[0].ti_Data = FALSE;
  632.             taglist[1].ti_Tag = AHIC_Record;    taglist[1].ti_Data = FALSE;
  633.             taglist[2].ti_Tag = TAG_DONE;          taglist[2].ti_Data = NULL;
  634.             if (ulError = AHI_ControlAudioA(AHIAudioControl, taglist))
  635.                 printf("AHI_ControlAudioA failed on stop, error %lu\n",ulError);
  636.             AHI_FreeAudio(AHIAudioControl); 
  637.             AHIAudioControl = NULL;
  638.         }
  639.         else printf("Um, AHIAudioControl was like, NULL or something\n");
  640.  
  641.         ulLastVolume = SILENCE;
  642.         return(FALSE);
  643.     }
  644. }
  645.  
  646.  
  647. /* Returns current state of the delfina sampler after operation attempted! */
  648. static BOOL StartDelfinaCapture(BOOL BStart, ULONG ulBPS)
  649. {
  650.     int compmode;
  651.     
  652.     if (BStart)
  653.     {
  654.         UNLESS(DelfinaBase) return(FALSE);
  655.  
  656.         ulSampleArraySize = ((CalcSampleArraySize(ulBPS, ubCurrComp, fPacketDelay) >> 4)+1)<<3;
  657.  
  658.         switch(ubCurrComp)
  659.         {
  660.             case COMPRESS_ADPCM2:    compmode = 1; break;
  661.             case COMPRESS_ADPCM3:    compmode = 2; break;
  662.             default:                compmode = 0; break;
  663.         }
  664.         /* Now allocate a buffer for us.  The >>3 is due to warts in AllocSamplingBuffer (read its header for more info) */
  665.         UNLESS(AllocSamplingBuffer(ulSampleArraySize>>3))
  666.         {
  667.             printf("StartDelfinaCapture():  Couldn't allocate sampling buffer!\n");
  668.             return(FALSE);
  669.         }
  670.         UNLESS(StartDelfina(ulBPS, ulSampleArraySize, compmode, (ubInputChannel == INPUT_JACK_RIGHT)))
  671.         {
  672.             printf("StartDelfinaCapture(): StartDelfina() failed!\n");
  673.             AllocSamplingBuffer(0);
  674.             return(FALSE);
  675.         }
  676.         return(TRUE);
  677.     }
  678.     else
  679.     {
  680.         StopDelfina();
  681.         AllocSamplingBuffer(0);    /* Free the mem we were using */
  682.         return(FALSE);
  683.     }    
  684. }
  685.  
  686.  
  687. /* BSTart controls whether to start or stop capture.  ulBPS is, of course,
  688.    the sampling rate (for the Toccata, this should be set to one of the
  689.    acceptable values--see toccata.doc) */
  690. static BOOL StartToccataCapture(BOOL BStart, ULONG ulBPS)
  691. {
  692.     static struct TagItem taglist[7];
  693.     ULONG ulTocArraySize;
  694.  
  695.     if (BStart)
  696.     {
  697.         UNLESS(ToccataBase) return(FALSE);
  698.  
  699.         /* Just to make sure... toccata docs say this is safe to call
  700.            even when we're not capturing */
  701.         T_Stop(TSF_DONTSAVECACHE);
  702.                 
  703.         pubBulkSamplePacket = NULL; 
  704.         UNLESS(ToccataReplyPort = CreatePort(0,0)) return(FALSE);
  705.  
  706.         /* Deallocate any RAM that was previously allocated */
  707.         /* We won't be using our buffer... toccata.library will provide one */
  708.         AllocSamplingBuffer(0L);
  709.  
  710.         /* check to see if hardware is really there! */
  711.         UNLESS(((struct ToccataBase *)ToccataBase)->tb_HardInfo)
  712.         {
  713.             SetWindowTitle("Error: No Toccata Hardware");
  714.             return(FALSE);
  715.         }
  716.  
  717.         /* We will allocate space for ulSmallestArraySize samples, @ 8 bits/sample */
  718.         /* The cool bit shifts and add are to round it up to the nearest 512-byte boundary */
  719.         /* The reason for >>10 instead of >>9 is to divide by two, as this represents only */
  720.         /* one of the two buffers that we would have had if we were using AmiPhone's double-buffer */
  721.         /* scheme */
  722.         ulTocArraySize = ((CalcSampleArraySize(ulBPS, ubCurrComp, fPacketDelay) >> 10)+1)<<9;
  723.  
  724.         /* Prepare taglist to send to T_Capture */
  725.         taglist[0].ti_Tag  = TT_BufferSize; taglist[0].ti_Data = ulTocArraySize;
  726.         taglist[1].ti_Tag  = TT_Save;        taglist[1].ti_Data = ToccataSendData;
  727.         taglist[2].ti_Tag  = TT_Mode;        taglist[2].ti_Data = TMODE_LINEAR_8;
  728.         taglist[3].ti_Tag  = TT_Frequency;  taglist[3].ti_Data = ulBPS;
  729.         taglist[4].ti_Tag  = TT_ErrorTask;  taglist[4].ti_Data = MainTask;
  730.         taglist[5].ti_Tag  = TT_ErrorMask;  taglist[5].ti_Data = SIGBREAKF_CTRL_D;
  731.         taglist[6].ti_Tag  = TAG_DONE;        taglist[6].ti_Data = NULL;
  732.  
  733.         /* and off it goes! */
  734.         UNLESS(T_Capture(taglist))
  735.         {
  736.             printf("StartToccataCapture: T_Capture failed, errno=%i\n",T_IoErr());
  737.             return(FALSE);
  738.         }
  739.         return(TRUE);
  740.     }
  741.     else
  742.     {
  743.         /* stop ze capture! */
  744.         T_Stop(TSF_DONTSAVECACHE);
  745.         pubBulkSamplePacket = NULL; 
  746.         RemovePortSafely(ToccataReplyPort); ToccataReplyPort = NULL;
  747.         ulLastVolume = SILENCE;
  748.         return(FALSE);    /* FALSE because we are returning the STATE of the sampler, not success/failure. */
  749.     }
  750. }
  751.  
  752.  
  753.  
  754. /* Called by AHI whenever data is to be xmitted */    
  755. static __geta4 ULONG AHISendData(struct Hook *hook, struct AHIAudioCtrl * ctrl, struct AHIRecordMessage * msg)
  756. {
  757.     pubBulkSamplePacket   = msg->ahirm_Buffer; 
  758.     ulSampleArraySize     = msg->ahirm_Length;
  759.  
  760.     ulBulkSamplePacketSum = ProcessAHIBuffer(pubBulkSamplePacket, &ulSampleArraySize, msg->ahirm_Type);
  761.     Signal(MainTask, SIGBREAKF_CTRL_F);
  762.     return(1);
  763. }
  764.  
  765.  
  766. /* called by the Toccata library whenever we need to send the data */
  767. static __geta4 BOOL ToccataSendData(UBYTE * pubData, ULONG ulDataSize)
  768. {    
  769.     pubBulkSamplePacket   = pubData;
  770.     ulSampleArraySize     = ulDataSize;
  771.  
  772.     ulBulkSamplePacketSum = ProcessToccataBuffer(pubData, ulDataSize);
  773.     Signal(MainTask, SIGBREAKF_CTRL_F);
  774.     return(TRUE);
  775. }
  776.  
  777.  
  778.  
  779.  
  780. /*
  781.  * This function attempts to raise the input gain by nSteps steps.
  782.  */
  783. void RaiseLineGain(int nSteps)
  784. {
  785.     char szMessage[60];
  786.     struct TagItem taglist[3];
  787.     int i, BRaise = (nSteps > 0);
  788.     
  789.     switch(ubSamplerType)
  790.     {
  791.        case SAMPLER_DELFINA:
  792.         nLineGainValue = ChopValue(nLineGainValue+nSteps,0,15);
  793.         taglist[0].ti_Tag = DA_InputGain;    taglist[0].ti_Data = (nLineGainValue * 0x10000)/15;
  794.         taglist[1].ti_Tag = TAG_DONE;        taglist[1].ti_Data = NULL;
  795.         Delf_SetAttrsA(taglist);
  796.         break;
  797.         
  798.        case SAMPLER_TOCCATA:
  799.         nLineGainValue = ChopValue(nLineGainValue+nSteps,0,15);    
  800.         taglist[0].ti_Tag  = PAT_InputVolumeRight; taglist[0].ti_Data = nLineGainValue;
  801.         taglist[1].ti_Tag  = PAT_InputVolumeLeft;  taglist[1].ti_Data = nLineGainValue;
  802.         taglist[2].ti_Tag  = TAG_DONE;            taglist[2].ti_Data = NULL;
  803.         T_SetPart(taglist);
  804.         break;
  805.         
  806.        case SAMPLER_GVPDSS8:
  807.         nLineGainValue = ChopValue(nLineGainValue+nSteps,0,7);
  808.             pciaa->ciaddrb  = 0xFF;    /* set data direction bits to output */
  809.         SetDirectionBits(SAMPBIT_BUSYSET);    /* busy bit as output */
  810.         SetParallelBits(EVENT_NONE, SAMPBIT_BUSYCLR);
  811.         pciaa->ciaprb = (nLineGainValue+8) | ((nLineGainValue+8) << 4);
  812.         SetParallelBits(EVENT_NONE, SAMPBIT_BUSYSET);
  813.         SetDirectionBits(SAMPBIT_BUSYCLR);
  814.             pciaa->ciaddrb  = 0x00;    /* data back to input */
  815.         break;
  816.         
  817.        case SAMPLER_PERFECT:
  818.         /* get absolute value */
  819.         nLineGainValue += nSteps;
  820.         if (nSteps < 0) nSteps *= -1;
  821.         for (i=0; i<nSteps; i++)
  822.         {
  823.             /* Set SEL to 0 for decrease, 1 for increase */
  824.             if (BRaise == TRUE) SetParallelBits(EVENT_NONE,SAMPBIT_SELSET);
  825.                        else SetParallelBits(EVENT_NONE,SAMPBIT_SELCLR);
  826.                 
  827.             /* Now toggle PB7 */
  828.                 pciaa->ciaprb  &= ~(0x80);    /* Gain control goes to zero */
  829.             Delay(1);
  830.                 pciaa->ciaprb  |= 0x80;        /* And back to one.  This is the trigger. */
  831.         }
  832.         ChangeInputChannel(ubInputChannel);    
  833.         break;
  834.     }
  835.     sprintf(szMessage,"Line Gain is now %i.", nLineGainValue);
  836.     SetWindowTitle(szMessage);
  837. }
  838.  
  839.  
  840. /*
  841.  * This function attempts to set the input gain of the microphone.
  842.  * Note the difference between this and RaiseLineGain.
  843.  *
  844.  */
  845. void SetMicGain(int nNewValue)
  846. {
  847.     char szMessage[40];
  848.     struct TagItem taglist[3];
  849.     
  850.     switch(ubSamplerType)
  851.     {
  852.        case SAMPLER_DELFINA:
  853.         taglist[0].ti_Tag = DA_MicIsLine;    taglist[0].ti_Data = (nNewValue==0);
  854.         taglist[1].ti_Tag = DA_HighPass;    taglist[1].ti_Data = (nNewValue==20);
  855.         taglist[2].ti_Tag = TAG_DONE;        taglist[2].ti_Data = NULL;
  856.         Delf_SetAttrsA(taglist);
  857.         break;
  858.  
  859.        case SAMPLER_TOCCATA:
  860.         taglist[0].ti_Tag  = PAT_MicGain;       taglist[0].ti_Data = (nNewValue > 0);
  861.         taglist[1].ti_Tag  = TAG_DONE;         taglist[1].ti_Data = NULL;
  862.         T_SetPart(taglist);
  863.         break;
  864.     }
  865.     
  866.     nMicGainValue = nNewValue;
  867.     sprintf(szMessage,"Microphone Gain is now +%idB.",nMicGainValue);
  868.     SetWindowTitle(szMessage);
  869. }
  870.  
  871.  
  872.  
  873. /* 
  874.  * This routine sets up the interval timer we allocated with
  875.  * AddICRVector().  Note that we may have alreay received one, or
  876.  * more interrupts from our timer.  Make no assumptions about the
  877.  * initial state of any of the hardware registers we will be using.
  878.  *
  879.  */
  880. static BOOL StartTimer(struct freetimer * ft, UWORD uwMicros, ULONG ulSmallestArraySize)
  881. {
  882.     register struct CIA * cia;
  883.  
  884.     /* Set parallel port direction register in CIA-A to "input" */
  885.     switch(ubSamplerType)
  886.     {
  887.         case SAMPLER_PERFECT:
  888.              pciaa->ciaddrb  = 0xC0;    /* high two bits are output/control bits on the PerfectSound! */
  889.              pciaa->ciaprb  |= 0xC0;    /* PB6, PB7 both high when sampling? */
  890.              SetDirectionBits(SAMPBIT_BUSYCLR);    /* per generic.source? */
  891.              break;
  892.                      
  893.         case SAMPLER_TOCCATA: case SAMPLER_AHI: case SAMPLER_DELFINA:
  894.              /* Don't call StartTimer() with these sampler types, fruit loop! */
  895.              return(FALSE);
  896.              break;
  897.         
  898.         case SAMPLER_SOMAGIC:
  899.              pciaa->ciaddrb  = 0x00;    /* all bits: input mode */
  900.              /* for this model, BUSY is used as an output also */
  901.              SetDirectionBits(SAMPBIT_SELSET | SAMPBIT_POUTSET | SAMPBIT_BUSYSET);
  902.              break; 
  903.         
  904.         case SAMPLER_CUSTOM:
  905.              /* Make all data bits input */
  906.              pciaa->ciaddrb  = 0x00;
  907.              /* User-customizable set of control direction bits */
  908.              SetDirectionBits(ubCustDir);
  909.              /* User-customizable set of control data bits */
  910.              SetParallelBits(EVENT_START, ubCustStart);
  911.              break;
  912.          
  913.         default:
  914.              pciaa->ciaddrb  = 0x00;    /* all bits: input mode */
  915.              SetDirectionBits(SAMPBIT_SELSET | SAMPBIT_POUTSET | SAMPBIT_BUSYCLR);
  916.              break;
  917.     }
  918.  
  919.     UNLESS(AllocSamplingBuffer(ulSmallestArraySize)) return(FALSE);
  920.     
  921.     IntData.pubSampleAt   = AMIGA_HARDWARE_SAMPLE_ADDRESS;        /* default = parallel hardware */
  922.     IntData.stTask        = FindTask(NULL);
  923.     IntData.ulHalfSignal  = (1<<sighalf);
  924.     IntData.ulFullSignal  = (1<<sigfull);
  925.     IntData.ulShiftLeft   = (ULONG) nAmpShift;
  926.     IntData.ulByteSum     = 0L;
  927.     IntData.ulSaveByteSum = 0L;
  928.     IntData.ulThreshhold  = (nPreSendQLen == 0) ? ((ULONG) ((nMinSampleVol*255)/100)) : 0L;
  929.     IntData.uwCiavals     = uwMicros;
  930.     IntData.uwClearCode   = (ft->BUsingCIAB) ? INTF_EXTER : INTF_PORTS;
  931.     IntData.BIdle          = 1L;
  932.     
  933.     ChangeInputChannel(ubInputChannel);    /* select channel for input if possible */
  934.  
  935.     ulLastVolume = SILENCE;    
  936.     TransmitData(0,0,0);
  937.         
  938.     /* Begin RKM timer startup code */    
  939.     cia = ft->cia;
  940.  
  941.     /* Note that there are differences between control register A,
  942.      * and B on each CIA (e.g. the TOD alarm bit, and INMODE bits. 
  943.      */
  944.  
  945.     if (ft->timerbit == CIAICRB_TA)
  946.     {
  947.         ft->ciacr = &cia->ciacra;        /* control register A */
  948.         ft->cialo = &cia->ciatalo;        /* low byte counter */
  949.         ft->ciahi = &cia->ciatahi;        /* high byte counter */
  950.         
  951.         ft->stopmask = STOPA_AND;        /* setup mask values */
  952.         ft->startmask = STARTA_OR;        
  953.     }
  954.     else
  955.     {
  956.         ft->ciacr = &cia->ciacrb;        /* control register B */
  957.         ft->cialo = &cia->ciatblo;        /* low byte counter */
  958.         ft->ciahi = &cia->ciatbhi;        /* high byte counter */
  959.         
  960.         ft->stopmask = STOPB_AND;        /* setup mask values */
  961.         ft->startmask = STARTB_OR;        
  962.     }
  963.  
  964.     IntData.pubCiahi      = ft->ciahi;
  965.     IntData.pubCialo      = ft->cialo;
  966.         
  967.     /* Modify control register within Disable().  This is done to avoid
  968.      * race conditions since our compiler may generate code such as:
  969.      *
  970.      *     value = Read hardware byte
  971.      *    AND value with MASK
  972.      *    Write value to hardware byte
  973.      *
  974.      * If we take a task switch in the middle of this sequence, two tasks
  975.      * trying to modify the same register could trash each others' bits.
  976.      *
  977.      * Normally this code would be written in assembly language using atomic
  978.      * instructions so that Disable() would not be needed.
  979.      */
  980.  
  981.     Disable();
  982.     
  983.     /* STOP timer, set 02 pulse countdown mode, set continuous mode */
  984.     
  985.     *ft->ciacr &= ft->stopmask;
  986.     
  987.     Enable();
  988.     
  989.     /* Start the interval timer - we will start the counter after 
  990.      * writing the low, and high byte counter values 
  991.      */
  992.     SetTimerCountdown(ft, (UWORD) BPSToMicros(ulIdleRate));
  993.     
  994.     /* Turn on start bit - same bit for both A, and B control regs */
  995.     Disable();
  996.     
  997.     *ft->ciacr |= ft->startmask;
  998.  
  999.     Enable();
  1000.     
  1001.     return(TRUE);
  1002. }
  1003.  
  1004.  
  1005.  
  1006. /* Allocate (or reallocate) the sampling buffer! */
  1007. /* Call with ulSize = 0 to free any allocated buffer! */
  1008. /* Allocates a buffer of size ulSmallestArraySize*8 bytes! */
  1009. /* (Yeah, that doesn't make sense, you're right!  But that's how it works) */
  1010. static BOOL AllocSamplingBuffer(ULONG ulSmallestArraySize)
  1011. {
  1012.     UBYTE * pubOldArray = pubAllocedArray;
  1013.     ULONG ulOldAllocedArraySize = ulAllocedArraySize;
  1014.     
  1015.     if (ulSmallestArraySize)
  1016.     {
  1017.         ulAllocedArraySize = ulSmallestArraySize<<3;    /* 8 bit recording == times 8 */
  1018.         UNLESS(pubAllocedArray = AllocMem(ulAllocedArraySize, MEMF_ANY))
  1019.         {
  1020.             /* oops--revert back to the old buffer */
  1021.             pubAllocedArray = pubOldArray;
  1022.             ulAllocedArraySize = ulOldAllocedArraySize;
  1023.             
  1024.             UserError("Couldn't allocate sampling buffer");
  1025.             return(FALSE);
  1026.         }
  1027.         pubRightBuffer = &pubAllocedArray[ulAllocedArraySize>>1];
  1028.     } 
  1029.     else  
  1030.     {
  1031.         /* 0 = de-alloc! */
  1032.         ulAllocedArraySize = 0L;
  1033.         pubAllocedArray = pubRightBuffer = NULL;
  1034.     }
  1035.  
  1036.     /* Initialize arg struct for inthandler */
  1037.     Disable();
  1038.     IntData.pubIndex      = pubAllocedArray;
  1039.     IntData.pubArray      = pubAllocedArray;
  1040.     if (pubAllocedArray)
  1041.     {
  1042.         IntData.pubHalfIndex  = &pubAllocedArray[ulAllocedArraySize/2];
  1043.         IntData.pubEndIndex   = &pubAllocedArray[ulAllocedArraySize-1];
  1044.     }
  1045.     else
  1046.     {
  1047.         IntData.pubHalfIndex  = NULL;
  1048.         IntData.pubEndIndex   = NULL;
  1049.     }
  1050.     Enable();
  1051.  
  1052.     /* Deallocate any RAM that was previously allocated */
  1053.     if (pubOldArray) FreeMem(pubOldArray, ulOldAllocedArraySize);
  1054.  
  1055.     return(TRUE);
  1056. }
  1057.  
  1058.  
  1059.  
  1060.  
  1061. /* If ft is NULL, use the same freetimer struct we used last time! */
  1062. void SetTimerCountdown(struct freetimer * ft, UWORD uwMicros)
  1063. {
  1064.     static struct freetimer * fLastTime = NULL;
  1065.     
  1066.     if (ft == NULL)
  1067.     {
  1068.         if (fLastTime == NULL) return;
  1069.         ft = fLastTime;
  1070.     } 
  1071.     else fLastTime = ft;
  1072.     
  1073.     Disable();
  1074.     *ft->ciahi = ((uwMicros & 0xFF00)>>8);
  1075.     *ft->cialo =  (uwMicros & 0x00FF)    ;
  1076.     Enable();
  1077. }
  1078.  
  1079.  
  1080.  
  1081. /*
  1082.  * A routine to find a free interval timer.
  1083.  *
  1084.  * This routine makes no assumptions about which interval timers
  1085.  * (if any) are available for use.  Currently there are two interval
  1086.  * timers per CIA chip.
  1087.  *
  1088.  * Because CIA usage may change in the future, you code should use
  1089.  * a routine like this to find a free interval timer.
  1090.  *
  1091.  * This routine will first try to get a timer on CIA-A, because that
  1092.  * CIA will not interfere with serial operations.  If that fails, it
  1093.  * will try for one on CIA-B.
  1094.  *
  1095.  */
  1096.  
  1097. static BOOL FindFreeTimer (struct freetimer *ft)
  1098. {
  1099.     struct CIABase * ciaabase, *ciabbase;
  1100.     
  1101.     /* get pointers to both resource bases--this doesn't tie anything up */
  1102.     ciaabase = OpenResource(CIAANAME);
  1103.     ciabbase = OpenResource(CIABNAME);
  1104.  
  1105.     /* Try for CIA-A */
  1106.     ft->ciabase = ciaabase;        /* library address for */
  1107.     ft->cia    = pciaa;
  1108.     ft->BUsingCIAB = FALSE;
  1109.     if (TryTimer(ft)) return(TRUE);
  1110.  
  1111.     /* Couldn't get CIA-A, try for CIA-B */
  1112.     ft->ciabase = ciabbase;
  1113.     ft->cia        = pciab;
  1114.     ft->BUsingCIAB = TRUE;
  1115.      return(TryTimer(ft));
  1116. }
  1117.  
  1118.  
  1119.  
  1120. /*
  1121.  * Try to obtain a free interval timer on a CIA.
  1122.  */
  1123.  
  1124. static BOOL TryTimer(struct freetimer * ft)
  1125. {
  1126.     if (!(AddICRVector(ft->ciabase,CIAICRB_TA,&ft->timerint)))
  1127.     {
  1128.         ft->timerbit = CIAICRB_TA;
  1129.         return(TRUE);
  1130.     }
  1131.     if (!(AddICRVector(ft->ciabase,CIAICRB_TB,&ft->timerint)))
  1132.     {
  1133.         ft->timerbit = CIAICRB_TB;
  1134.         return(TRUE);
  1135.     }
  1136.     return(FALSE);
  1137. }
  1138.  
  1139.  
  1140. /* public functions */
  1141. /* returns success, or if BAlloc == CHECK_STATUS, returns TRUE if
  1142.    available, FALSE if not */
  1143. /* Don't call this manually except to check_status!  StartSampling
  1144.    will call it as necessary! */
  1145. BOOL AllocParallel(BOOL BAlloc, BOOL BGrab)
  1146. {
  1147.     char * szCurrentUser;
  1148.     char * pcErrType = (BAlloc == CHECK_STATUS) ? "Warning:" : "Error:";
  1149.     char szMessage[50];
  1150.     static char szAllocName[30];
  1151.     
  1152.     if ((BAlloc == TRUE)||(BAlloc == CHECK_STATUS))
  1153.     {
  1154.         sprintf(szAllocName,"AmiPhone_%ld",ulKeyCode);
  1155.  
  1156.         szCurrentUser = AllocMiscResource(MR_PARALLELPORT, szAllocName);
  1157.         if (szCurrentUser != NULL) 
  1158.         {
  1159.             /* If another AmiPhone is using the parallel, we'll try to kick them off! */
  1160.             if ((BGrab == TRUE)&&(strncmp(szCurrentUser, "AmiPhone", 8) == 0)&&
  1161.                 (TellOtherAmiPhoneToLetGo(szCurrentUser) == TRUE)) 
  1162.                 {
  1163.                     Delay(5);    /* allow the other guy time to disengage */
  1164.                     return(AllocParallel(TRUE, FALSE));
  1165.                 }
  1166.             
  1167.             sprintf(szMessage,"%s Parallel port in use.",pcErrType);
  1168.             SetWindowTitle(szMessage);    
  1169.             
  1170.             return(FALSE);
  1171.         }
  1172.         szCurrentUser = AllocMiscResource(MR_PARALLELBITS, szAllocName);
  1173.         if (szCurrentUser != NULL) 
  1174.         {
  1175.             FreeMiscResource(MR_PARALLELPORT);        /* clean up! */
  1176.             sprintf(szMessage,"%sParallel bits in use.",pcErrType);
  1177.             SetWindowTitle(szMessage);
  1178.             return(FALSE);        
  1179.         }
  1180.     }
  1181.     
  1182.     if ((BAlloc == FALSE)||(BAlloc == CHECK_STATUS))    
  1183.     {        
  1184.         FreeMiscResource(MR_PARALLELBITS);         
  1185.         FreeMiscResource(MR_PARALLELPORT);
  1186.     }            
  1187.     return(TRUE);
  1188. }
  1189.  
  1190. BOOL TellOtherAmiPhoneToLetGo(char * szOtherPhoneName)
  1191. {
  1192.     static struct AmiPhoneInfo ReleaseMsg;
  1193.     
  1194.     ReleaseMsg.ubControl = MSG_CONTROL_RELEASE;
  1195.     return(SafePutToPort((struct Message *) &ReleaseMsg, szOtherPhoneName));
  1196. }
  1197.  
  1198.  
  1199. BOOL AllocSignals(BOOL BAlloc)
  1200. {
  1201.     if (BAlloc == TRUE)
  1202.     {
  1203.         if ((sighalf == 0)&&(sigfull == 0))
  1204.         {
  1205.             /* Try to allocate signal bytes */
  1206.             sighalf = AllocSignal(-1);
  1207.             if (sighalf == -1) return(FALSE);
  1208.             sigfull = AllocSignal(-1);
  1209.             if (sigfull == -1) return(FALSE);
  1210.  
  1211.         }
  1212.         else return(FALSE);
  1213.     }
  1214.     else
  1215.     {
  1216.         if (sigfull != 0) {FreeSignal(sigfull);     sigfull = 0;}
  1217.         if (sighalf != 0) {FreeSignal(sighalf);  sighalf = 0;}
  1218.     }    
  1219.     return(TRUE);    
  1220. }
  1221.  
  1222.  
  1223. /* Returns the number of bytes that should be in our
  1224.    sampling array for this given BPS, compression scheme
  1225.    and packet length. */
  1226. static ULONG CalcSampleArraySize(ULONG ulBPS, BYTE bComp, float fPacketDelayArg)
  1227. {
  1228.     ULONG ulTemp;
  1229.     float fTemp;
  1230.     float fKludge = 0.0f;
  1231.     int i;
  1232.     
  1233.     /* simulate multiply through adding!? */
  1234.     /* originally: ulTemp = (ULONG)((((float)ulBPS) * fDelay)/(4.0)); */
  1235.     
  1236.     fTemp = ((float) ulBPS);    
  1237.     for (i=0;i<ulBPS;i++) fKludge += fPacketDelayArg;
  1238.     fTemp = fKludge;
  1239.     ulTemp = (ULONG) fTemp;
  1240.     ulTemp >>= 2;
  1241.  
  1242.     /* compression algorithm specific size restrictions implemented here */    
  1243.     switch(bComp)
  1244.     {
  1245.         case COMPRESS_ADPCM2: while (ulTemp % 2) ulTemp++; break;
  1246.         case COMPRESS_ADPCM3: while (ulTemp % 3) ulTemp++; break;
  1247.         case COMPRESS_NONE:   while (ulTemp % 2) ulTemp++; break;
  1248.     }
  1249.     return(ulTemp);
  1250. }
  1251.  
  1252.  
  1253. void ChangeCompressMode(UBYTE ubNewMode)
  1254. {
  1255.     ubCurrComp = ubNewMode;
  1256.     
  1257.     /* Force reset! */
  1258.     if (ubSamplerType == SAMPLER_DELFINA) ChangeSampleSpeed(ulBytesPerSecond, ubCurrComp);
  1259. }
  1260.  
  1261.  
  1262.  
  1263. ULONG ChangeSampleSpeed(ULONG ulNewBPS, UBYTE bComp)
  1264. {
  1265.     /* If we're sampling with the Toccata board, change it to the nearest rate we can handle */
  1266.     if ((ToccataBase)&&(ubSamplerType == SAMPLER_TOCCATA)) 
  1267.     {
  1268.         ulNewBPS = T_FindFrequency(ulNewBPS);
  1269.         if ((ulNewBPS == 0)||(ulNewBPS > nMaxSampleRate)) ulNewBPS = T_FindFrequency(0);
  1270.     }
  1271.     if (ubSamplerType == SAMPLER_DELFINA) ulNewBPS = GetClosestDelfRate(ulNewBPS, NULL, NULL);
  1272.     if ((ubSamplerType == SAMPLER_AHI)&&(ulAHIAudioMode)) ulNewBPS = AHI_FindFrequency(ulNewBPS);
  1273.  
  1274.     /* make sure our sampling isn't too fast or too slow */
  1275.     if (UsesCIAInterrupt())
  1276.             ulNewBPS = ChopValue(ulNewBPS, MIN_SAMPLE_RATE, nMaxSampleRate);
  1277.  
  1278.     /* make sure our packets aren't too small  */
  1279.     if (fPacketDelay < MIN_PACKET_INTERVAL) fPacketDelay = MIN_PACKET_INTERVAL;
  1280.  
  1281.     /* To keep a particular speed, add this:         */
  1282.     /* if (bComp == COMPRESS_SDP1) ulNewBPS = 6000L; */
  1283.  
  1284.     /* Calculate array size based on samples/sec and packet delay */
  1285.     ulSampleArraySize = CalcSampleArraySize(ulNewBPS, bComp, fPacketDelay);
  1286.  
  1287.     if (StartSampling(CHECK_STATUS,0) == TRUE)
  1288.     {
  1289.         if (UsesCIAInterrupt())
  1290.         {
  1291.             /* With the CIA, we can change rates on the fly! */
  1292.             ulTimerDelay = BPSToMicros(ulNewBPS);
  1293.             UNLESS(AllocSamplingBuffer(ulSampleArraySize)) return(FALSE);
  1294.             
  1295.             Disable();
  1296.             IntData.uwCiavals     = ulTimerDelay;
  1297.             IntData.ulThreshhold  = (ULONG) (nMinSampleVol*255)/100;
  1298.             UNLESS(IntData.BIdle) SetTimerCountdown(NULL,ulTimerDelay);
  1299.             Enable();
  1300.             
  1301.             ulLastVolume = SILENCE;
  1302.         }
  1303.         else
  1304.         {
  1305.             /* Make no assumptions--stop & restart other boards */
  1306.             BTransmitting = StartSampling(FALSE,0);
  1307.             BTransmitting = StartSampling(TRUE,ulNewBPS);
  1308.         }
  1309.     }
  1310.     return(ulBytesPerSecond = ulNewBPS);
  1311. }
  1312.  
  1313.  
  1314.  
  1315. /* Go through and make the bytes in the buffer unsigned,
  1316.    and add up their total and return it as well */
  1317. ULONG ProcessToccataBuffer(UBYTE * pubData, ULONG ulDataLen)
  1318. {
  1319.     register ULONG ulSum = 0L;
  1320.     register UBYTE ubTemp;
  1321.     register UBYTE * pubCurrent = pubData;
  1322.     register ULONG ulLeft = ulDataLen;
  1323.         
  1324.     while(ulLeft--)
  1325.     {
  1326.         ubTemp = ((*pubCurrent)-128)<<nAmpShift;
  1327.         *pubCurrent = ubTemp;
  1328.         ulSum += ubTemp; pubCurrent++;
  1329.     }
  1330.     return(ulSum);
  1331. }
  1332.  
  1333.  
  1334. /* Turn the words in the buffer into bytes.  Note that the
  1335.    ulDataLen parameter is the length of the buffer in BYTES,
  1336.    and when the function returns, only the first half of
  1337.    the buffer will be valid. */
  1338. /* Returns the sample sum, just like ProcessToccataBuffer() */
  1339.  
  1340. /* pubData    - pointer to the sampled buffer */
  1341. /* ulDataLen  - in/out variable, sends in length of buffer at current
  1342.         bit-width, etc... returns out the length of buffer 
  1343.         in 8-bit mono */
  1344. /* ulType     - The data type as given by AHI */
  1345. ULONG ProcessAHIBuffer(UBYTE * pubData, ULONG * ulDataLen, ULONG ulType)
  1346. {
  1347.     register ULONG ulSum = 0L;
  1348.     register UBYTE ubTemp, ubReadDiff;
  1349.     register UBYTE * pubCurrentRead  = pubData;
  1350.     register UBYTE * pubCurrentWrite = pubData;
  1351.     register ULONG ulLeft;
  1352.     
  1353.     switch(ulType)
  1354.     {
  1355.         case AHIST_M8S:   /* Mono, 8 bit signed (BYTE) */
  1356.             ubReadDiff = 1;
  1357.             break;
  1358.                                 
  1359.         case AHIST_M8U:   /* Mono, 8 bit unsigned (UBYTE) */
  1360.             ubReadDiff = 1;
  1361.             break;
  1362.             
  1363.         case AHIST_M16S:  /* Mono, 16 bit signed (WORD) */
  1364.             ubReadDiff = 2;
  1365.             break;
  1366.             
  1367.         case AHIST_S16S:  /* Stereo 16 bit signed (2×WORD) */
  1368.             ubReadDiff = 4;
  1369.             if (ubInputChannel == INPUT_JACK_RIGHT) pubCurrentRead += 2;
  1370.             break;
  1371.     
  1372.         default:      /* error! */
  1373.             return(1L);
  1374.             break;
  1375.     }
  1376.     
  1377.     *ulDataLen = ulLeft = (*ulDataLen)/ubReadDiff;
  1378.     
  1379.     while(ulLeft--)
  1380.     {
  1381.         ubTemp = ((*pubCurrentRead)-128)<<nAmpShift;
  1382.         ulSum += ubTemp;
  1383.         *pubCurrentWrite = ubTemp;
  1384.         pubCurrentRead += ubReadDiff; pubCurrentWrite++;
  1385.     }
  1386.     return(ulSum);
  1387. }
  1388.  
  1389.  
  1390. /* Given a byte-count, returns a volume percentage between 0 and 100. */
  1391. /* Note that, if the CIA Interrupt is used, that ulSampleArraySize is
  1392.    the size of BOTH buffers, and we want to use the size of just one,
  1393.    so we divide ulSampleArraySize by 2. */
  1394. int CalcVolumePercentage(ULONG ulVolume)
  1395.     ULONG ulVol, ulMaxArrayCount;
  1396.     int nResult;
  1397.     
  1398.     if (UsesCIAInterrupt())
  1399.     {
  1400.         ulMaxArrayCount = ulSampleArraySize << 6;
  1401.         ulVolume >>= 4;    /* It's still a mystery to me why this is 16 times too big! */
  1402.     }
  1403.     else
  1404.     {
  1405.         ulMaxArrayCount = ulSampleArraySize << 7;
  1406.     }
  1407.     
  1408.     if (UsesInvertedSamples())
  1409.     {
  1410.         ulVol = ((ulMaxArrayCount > ulVolume) ? (ulMaxArrayCount-ulVolume) : 0L);
  1411.     }
  1412.     else
  1413.     {
  1414.         ulVol = ulVolume;
  1415.     }
  1416.  
  1417.     /* Per-sampler, hacky stuff.  Ewww! */
  1418.     switch(ubSamplerType)
  1419.     {
  1420.         case SAMPLER_GVPDSS8:    ulVol <<= 1; break;
  1421.         case SAMPLER_TOCCATA:   ulVol <<= 2; break;
  1422.     }
  1423.     
  1424.     if (nHackAmpVol != 1000) ulVol = (ulVol * nHackAmpVol)/1000;
  1425.     nResult = (ulVol*100)/ulMaxArrayCount;
  1426.  
  1427.     if (BUserDebug)
  1428.     {
  1429.         printf("Vol Percent=%i%% (ulVol=%lu (orig.%lu), ulMaxCount=%lu (BufSize=%lu) (st=%i)\n", 
  1430.             nResult, ulVol, ulVolume, ulMaxArrayCount, ulSampleArraySize, ubSamplerType);
  1431.     }
  1432.  
  1433.     return(nResult);
  1434. }
  1435.  
  1436.  
  1437. /* If nBytes == ALL_OF_BUFFER, transmit the whole buffer section.
  1438.    Otherwise, transmit the first nBytes of the indicated buffer. */   
  1439. void TransmitData(UBYTE * pubStart, int nBytes, int bComp)
  1440. {
  1441.     ULONG ulLength;
  1442.     BOOL BSoundWasOnBefore = BSoundOn;
  1443.     static ULONG ulSaveJoin = 0L, ulJoinCode = 0L;
  1444.     static int nPostGracePeriod = nPostSendLen;
  1445.             
  1446.     if (nBytes == 0)
  1447.     {
  1448.         IdleSampler();
  1449.         nPostGracePeriod = 0;
  1450.         BSoundOn = FALSE;
  1451.         return;
  1452.     }
  1453.  
  1454.     /* Was there enough sound there to transmit? */
  1455.     if (ubSamplerType == SAMPLER_DELFINA)
  1456.         ulLastVolume = IntData.ulSaveByteSum = DelfPacket(sendBuf.ubData, nBytes, &ulSaveJoin);
  1457.        else ulLastVolume = IntData.ulSaveByteSum;
  1458.        
  1459.     if (CalcVolumePercentage(ulLastVolume) < nMinSampleVol)
  1460.     {
  1461.         /* This section entered if the current buffer is too quiet */
  1462.         if (nPostGracePeriod > 0) 
  1463.              nPostGracePeriod--; /* time is running out to hear something! */
  1464.         else BSoundOn = FALSE;     /* time's up!  Shut off the transmission! */
  1465.     }
  1466.     else 
  1467.     {
  1468.         /* This section entered if the current buffer is loud enough */
  1469.         nPostGracePeriod = nPostSendLen;
  1470.         BSoundOn = TRUE;
  1471.     }
  1472.     
  1473.     UNLESS(BSoundOn)
  1474.     {
  1475.         IdleSampler();
  1476.         
  1477.         /* and tell the daemon to flush the buffers */
  1478.         if (BSoundWasOnBefore == TRUE) SendCommandPacket(PHONECOMMAND_FLUSH,0,0L);
  1479.     }
  1480.     
  1481.     ulLength = (nBytes == ALL_OF_BUFFER) ? (ulAllocedArraySize>>1) : nBytes;
  1482.         
  1483.     /* prepare the bytes if they are loud enough and we're enabled to xmit,
  1484.        or we need them to be queued.  */
  1485.     if (((BSoundOn)&&(BTransmitting))||(nPreSendQLen > 0))
  1486.     {
  1487.         /* Prepare/compress the packet */
  1488.         sendBuf.header.ubCommand  = PHONECOMMAND_DATA;
  1489.         sendBuf.header.ubType     = bComp;
  1490.         sendBuf.header.ulBPS      = ulBytesPerSecond;
  1491.         sendBuf.header.ulJoinCode = ulJoinCode;
  1492.  
  1493.         if (ubSamplerType == SAMPLER_DELFINA)
  1494.         {
  1495.             /* Compression was done by the Delfina's DSP, 
  1496.                all we need to do here is get the next ulJoinCode */
  1497.             sendBuf.header.ulDataLen = nBytes;
  1498.         }
  1499.         else
  1500.         {
  1501.             /* Do the compression ourselves! */
  1502.             sendBuf.header.ulDataLen  = CompressData(pubStart,sendBuf.ubData,bComp,ulLength,&ulJoinCode);
  1503.         }    
  1504.     }
  1505.  
  1506.     /* Now either send if we got something, or queue if we don't
  1507.        (and we are set to queue!) */
  1508.     if ((BSoundOn)&&(BTransmitting))
  1509.     {
  1510.         /* Send the data out */
  1511.         if (nPreSendQLen > 0) FlushPreSendQueue(TRUE, BTCPBatchXmit);
  1512.         (void)SendPacket(&sendBuf,BTCPBatchXmit);
  1513.     }
  1514.     else if (nPreSendQLen > 0)
  1515.     {
  1516.         /* Pack up the packet to go, and queue it */
  1517.         UpdatePreSendQueue(&sendBuf);
  1518.     }    
  1519.  
  1520.     /* For Delfina:  *Now* update ulJoinCode, AFTER we've set sendBuf.header.ulJoinCode */
  1521.     if (ubSamplerType == SAMPLER_DELFINA) ulJoinCode = ulSaveJoin;
  1522.  
  1523.     /* If we're doing hold-to-transmit and button is no longer being held, turn sampler off */
  1524.     if ((nToggleMode == TOGGLE_HOLD)&&(BButtonHeld == FALSE)) ToggleMicButton(CODE_OFF);
  1525.  
  1526.     /* Don't let one space tap cause more than one packet to be sampled */
  1527.     if (BSpaceTapped == TRUE) BSpaceTapped = BButtonHeld = FALSE;
  1528.         
  1529.     /* update MicButton image */
  1530.     nAnimFrame = (nAnimFrame+1)%4;
  1531.     DrawMicButton(-1);
  1532. }
  1533.  
  1534. /* Returns STATE of the PreSend queue! */
  1535. BOOL SetupPreSendQueue(BOOL BSetup)
  1536. {
  1537.     if (BSetup)
  1538.     {
  1539.         UNLESS(PreSendQueue = AllocMem(sizeof(struct List), MEMF_ANY)) return(FALSE);
  1540.         NewList(PreSendQueue);
  1541.         nCurrentPreSendQLen = 0;
  1542.         return(TRUE);
  1543.     }
  1544.     else
  1545.     {
  1546.         if (PreSendQueue)
  1547.         {
  1548.             FlushPreSendQueue(FALSE, FALSE);
  1549.             FreeMem(PreSendQueue, sizeof(struct List));
  1550.             PreSendQueue = NULL;
  1551.         }
  1552.         return(FALSE);    
  1553.     }
  1554. }
  1555.  
  1556. /* Empty the presend queue, either with or without transmitting packets */
  1557. void FlushPreSendQueue(BOOL BTransmit, BOOL BTCP)
  1558. {    
  1559.     struct Node * current;
  1560.     
  1561.     while(current = RemHead(PreSendQueue))
  1562.     {
  1563.         if (BTransmit) SendPacket((struct AmiPhoneSendBuffer *)current->ln_Name, BTCP);
  1564.         FreePreSendNode(current);
  1565.     }
  1566. }
  1567.  
  1568. void FreePreSendNode(struct Node * current)
  1569. {
  1570.     struct AmiPhoneSendBuffer * packet = current->ln_Name;
  1571.  
  1572.     FreeMem(packet, sizeof(struct AmiPhonePacketHeader)+packet->header.ulDataLen);
  1573.     FreeMem(current, sizeof(struct Node));    
  1574.     nCurrentPreSendQLen--;
  1575. }
  1576.  
  1577. void UpdatePreSendQueue(struct AmiPhoneSendBuffer * sBuf)
  1578. {
  1579.     struct AmiPhoneSendBuffer * newPacket;
  1580.     struct Node * newnode;
  1581.     ULONG ulPacketLen;
  1582.  
  1583.     if (nPreSendQLen == 0) return;    /* 0 == no queueing done */
  1584.     
  1585.     ulPacketLen = sBuf->header.ulDataLen + sizeof(struct AmiPhonePacketHeader);
  1586.     
  1587.     /* First, remove and free items from the queue until the
  1588.        queue is below the maximum size */
  1589.     while (nCurrentPreSendQLen >= nPreSendQLen)
  1590.         FreePreSendNode(RemHead(PreSendQueue));
  1591.  
  1592.     /* Now make a copy of sBuf and append it to the queue */
  1593.     UNLESS(newnode = AllocMem(sizeof(struct Node), MEMF_CLEAR)) return;
  1594.     UNLESS(newPacket = AllocMem(ulPacketLen, MEMF_ANY))
  1595.     {
  1596.         FreeMem(newnode, sizeof(struct Node));
  1597.         return;
  1598.     }
  1599.     
  1600.     memcpy(newPacket, sBuf, ulPacketLen);
  1601.     newnode->ln_Name = newPacket;
  1602.     AddTail(PreSendQueue, newnode);
  1603.     nCurrentPreSendQLen++;
  1604. }
  1605.  
  1606.  
  1607.  
  1608. static void IdleSampler(void)
  1609. {
  1610.     /* Back to idle mode */
  1611.     if (UsesCIAInterrupt())
  1612.     {
  1613.         Disable();
  1614.         IntData.BIdle = 1L;
  1615.         SetTimerCountdown(NULL, BPSToMicros(ulIdleRate));
  1616.         Enable();
  1617.     }
  1618. }
  1619.  
  1620.  
  1621.  
  1622. /* Sets the values of the POUT, SEL, and BUSY bits as given by the
  1623.    code ubBitCode. */
  1624. #define SETCIA(x) (pciab->ciapra|=(x))
  1625. #define CLRCIA(x) (pciab->ciapra&=~(x))
  1626. static void SetParallelBits(int nEvent, UBYTE ubBitCode)
  1627. {
  1628.     if (ubBitCode == 0) return;
  1629.     if (ubBitCode & SAMPBIT_POUTCLR) CLRCIA(CIAF_PRTRPOUT);
  1630.     if (ubBitCode & SAMPBIT_POUTSET) SETCIA(CIAF_PRTRPOUT);
  1631.     
  1632.     if (ubBitCode & SAMPBIT_SELCLR)  CLRCIA(CIAF_PRTRSEL);
  1633.     if (ubBitCode & SAMPBIT_SELSET)  SETCIA(CIAF_PRTRSEL);
  1634.     
  1635.     if (ubBitCode & SAMPBIT_BUSYCLR) CLRCIA(CIAF_PRTRBUSY);
  1636.     if (ubBitCode & SAMPBIT_BUSYSET) SETCIA(CIAF_PRTRBUSY);
  1637.     
  1638.     if (nEvent > EVENT_NONE) printf("SetParallelBits: (%s) Executed code %s, control bits are now %s.\n",
  1639.        szEventStrings[nEvent], BitsToString(ubBitCode), RegToString(pciab->ciapra));
  1640. }
  1641.  
  1642. /* Sets the values of the POUT, SEL, and BUSY bits for the data
  1643.    direction register, as given by the code ubBitCode. */
  1644. #define SETDCIA(x) (pciab->ciaddra|=(x))
  1645. #define CLRDCIA(x) (pciab->ciaddra&=~(x))
  1646. static void SetDirectionBits(UBYTE ubBitCode)
  1647. {
  1648.     if (ubBitCode == 0) return;
  1649.     if (ubBitCode & SAMPBIT_POUTCLR) CLRDCIA(CIAF_PRTRPOUT);
  1650.     if (ubBitCode & SAMPBIT_POUTSET) SETDCIA(CIAF_PRTRPOUT);
  1651.     
  1652.     if (ubBitCode & SAMPBIT_SELCLR)  CLRDCIA(CIAF_PRTRSEL);
  1653.     if (ubBitCode & SAMPBIT_SELSET)  SETDCIA(CIAF_PRTRSEL);
  1654.     
  1655.     if (ubBitCode & SAMPBIT_BUSYCLR) CLRDCIA(CIAF_PRTRBUSY);
  1656.     if (ubBitCode & SAMPBIT_BUSYSET) SETDCIA(CIAF_PRTRBUSY);
  1657.  
  1658.     if ((ubSamplerType == SAMPLER_CUSTOM)&&
  1659.         (ubBitCode != (SAMPBIT_POUTSET | SAMPBIT_SELSET | SAMPBIT_BUSYSET))) printf("SetDirectionBits:  Executed %s, direction bits are now %s\n",BitsToString(ubBitCode),RegToString(pciab->ciaddra));
  1660. }
  1661.  
  1662. /* Returns the changes a given byte code will do/has done. */
  1663. static char * BitsToString(UBYTE ubCode)
  1664. {
  1665.     static char szResult[13];
  1666.     
  1667.     memset(szResult,0,sizeof(szResult));
  1668.     if (ubCode & SAMPBIT_POUTCLR) strcat(szResult,"-P");
  1669.     if (ubCode & SAMPBIT_POUTSET) strcat(szResult,"+P");
  1670.     if (ubCode & SAMPBIT_SELCLR)  strcat(szResult,"-S");
  1671.     if (ubCode & SAMPBIT_SELSET)  strcat(szResult,"+S");
  1672.     if (ubCode & SAMPBIT_BUSYCLR) strcat(szResult,"-B");
  1673.     if (ubCode & SAMPBIT_BUSYSET) strcat(szResult,"+B");
  1674.     return(szResult);
  1675. }
  1676.  
  1677. /* Returns the state of the register. */
  1678. static char * RegToString(UBYTE ubReg)
  1679. {
  1680.     static char szResult[25];
  1681.     
  1682.     sprintf(szResult,"P=%i,B=%i,S=%i",
  1683.         (ubReg & CIAF_PRTRPOUT) != 0,
  1684.         (ubReg & CIAF_PRTRBUSY) != 0,
  1685.         (ubReg & CIAF_PRTRSEL)  != 0);
  1686.     
  1687.     return(szResult);
  1688. }
  1689.  
  1690.  
  1691. /* Should work much like Toccata's T_FindFrequency function ... */
  1692. static ULONG AHI_FindFrequency(ULONG ulBPS)
  1693. {
  1694.     ULONG ulIndex=0, ulFreq=0;
  1695.     struct TagItem taglist[3];
  1696.  
  1697.     taglist[0].ti_Tag  = AHIDB_Index;     taglist[0].ti_Data  = &ulIndex;
  1698.     taglist[1].ti_Tag  = AHIDB_IndexArg;     taglist[1].ti_Data  = ulBPS;
  1699.     taglist[2].ti_Tag  = TAG_DONE;        taglist[2].ti_Data  = NULL;
  1700.     if (AHI_GetAudioAttrsA(ulAHIAudioMode, NULL, taglist))
  1701.     {
  1702.         printf("AHI_FindFrequency: Nearest index = %lu\n",ulIndex);
  1703.         taglist[0].ti_Tag  = AHIDB_Frequency;     taglist[0].ti_Data  = &ulFreq;
  1704.         taglist[1].ti_Tag  = AHIDB_FrequencyArg;taglist[1].ti_Data  = ulIndex;
  1705.         if (AHI_GetAudioAttrsA(ulAHIAudioMode, NULL, taglist))
  1706.         {
  1707.             printf("AHI_FindFrequency: Frequency to use:  %lu\n",ulFreq);
  1708.             return(ulFreq);
  1709.         }
  1710.     }
  1711.     return(1L);
  1712. }
  1713.